package org.lgh.webchatback.netty;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.lgh.webchatback.enums.MsgActionEnum;
import org.lgh.webchatback.service.UserService;
import org.lgh.webchatback.utils.JsonUtils;
import org.lgh.webchatback.utils.SpringUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author wei-xhh
 * @date 2022-02-08
 * 处理消息
 * 由于它的传输数据的载体是Frame,这个frame在netty中
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 获取客户端所传输的消息
        String content = msg.text();
        System.out.println("接受到的数据:" + content);

        // 获取客户端发来的消息
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        Integer action = dataContent.getAction();
        // 判断消息类型，根据不同的类型来处理不同的业务
        /*
         * 当websocket 第一次打开的时候，初始化channel，把用的channel和userid关联起来
         * 聊天类型的信息，把聊天记录保存到数据库，同时标记消息的签收状态
         * 签收消息类型，针对具体的消息进行签收，修改数据库中对应的签收状态
         * 心跳类型的消息
         */
        Channel channel = ctx.channel();
        if (action == MsgActionEnum.CONNECT.type) {
            String senderId = dataContent.getChatMsg().getSenderId();
            UserChannelRel.put(senderId, channel);
        } else if (action == MsgActionEnum.CHAT.type) {
            ChatMsg chatMsg = dataContent.getChatMsg();
            String msgContent = chatMsg.getMsg();
            String senderId = chatMsg.getSenderId();
            String receiverId = chatMsg.getReceiverId();
            // 保存消息到数据库，并且标记未签收
            UserService userService = (UserService) SpringUtil.getBean("userServiceImpl");
            String msgId = userService.saveMsg(chatMsg);
            chatMsg.setMsgId(msgId);

            DataContent dataContentMsg = new DataContent();
            dataContentMsg.setChatMsg(chatMsg);

            // 发送消息
            Channel receiverChannel = UserChannelRel.get(receiverId);
            if (receiverChannel == null) {
                // 离线用户
            } else {
                Channel findChannel = clients.find(receiverChannel.id());
                if (findChannel != null) {
                    // 用户在线
                    receiverChannel.writeAndFlush(
                            new TextWebSocketFrame(JsonUtils.objectToJson(dataContent)));
                } else {
                    // 离线用户
                }
            }

        } else if (action == MsgActionEnum.SIGNED.type) {
            UserService userService = (UserService) SpringUtil.getBean("userServiceImpl");
            String msgIdsStr = dataContent.getExtend();
            String[] msgsId = msgIdsStr.split(",");

            List<String> msgIdList = new ArrayList<>();
            for (String s : msgsId) {
                if(StringUtils.isNotBlank(s)) {
                    msgIdList.add(s);
                }
            }
            System.out.println(msgIdList.toString());
            if(!msgIdList.isEmpty()) {
                userService.updateMsgSigned(msgIdList);
            }
        } else if (action == MsgActionEnum.KEEPALIVE.type) {

        }

    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        clients.remove(ctx.channel());
        System.out.println("客户端断开，channel对应的长Id为:" + ctx.channel().id().asLongText());
        System.out.println("客户端断开，channel对应的短Id为:" + ctx.channel().id().asShortText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
        clients.remove(ctx.channel());
    }
}
